/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.request.admin.ServiceRequestMessage;
import cn.easyplatform.messages.vos.admin.ServiceVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ServiceType;
import cn.easyplatform.type.StateType;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.service.ServiceLocator;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class UserController extends SelectorComposer<Component> {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @Wire("grid#users")
    private Grid users;

    @Wire("label#nums")
    private Label nums;

    private List<ServiceVo> model;

    private EventListener el = event -> {
        int evt = (int) event.getTarget().getAttribute("s");
        if (evt == 0)
            onLock(event);
        else if (evt == 2)
            onShowLog(event);
        else if (evt == 1)
            onStop(event);
        else if (evt == 3)
            onWorkbench(event);
    };

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(new SimpleRequestMessage(ServiceType.USER));
        if (resp.isSuccess()) {
            model = (List<ServiceVo>) resp.getBody();
            nums.setValue(Labels.getLabel("admin.user.nums") + ":" + model.size());
            createList(model);
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }

    private void createList(List<ServiceVo> list) {
        for (ServiceVo s : list) {
            Row row = new Row();
            row.appendChild(new Label(s.getId()));
            row.appendChild(new Label(s.getName()));
            row.appendChild(new Label(s.getAsString("ip")));
            row.appendChild(new Label(DateFormatUtils.format(s.getAsDate("time"), "yyyy-MM-dd HH:mm:ss")));
            row.appendChild(new Label(DateFormatUtils.format(s.getAsDate("lastAccessTime"), "yyyy-MM-dd HH:mm:ss")));
            row.appendChild(new Label((Nums.toInt(s.getValue("timeout"), 0) / 1000) + Labels.getLabel("fx.second")));
            row.appendChild(new Label(Labels.getLabel("admin.user.type." + s.getType())));
            row.appendChild(new Label(s.getAsString("org")));
            row.appendChild(new Label(s.getAsString("role")));
            row.appendChild(new Label(s.getAsString("client")));
            row.appendChild(new Label(s.getAsString("session")));
            Span span = new Span();
            Button op = new Button();
            if (s.getState() == StateType.START) {
                op.setIconSclass("z-icon-cog z-icon-spin");
                op.setLabel(Labels.getLabel("admin.service.state.blocked"));
            } else if (s.getState() == StateType.PAUSE) {
                op.setIconSclass("z-icon-lock");
                op.setLabel(Labels.getLabel("admin.service.state.paused"));
            }
            op.setAttribute("s", 0);
            op.addEventListener(Events.ON_CLICK, el);
            op.setParent(span);

            Button stop = new Button(Labels.getLabel("button.remove"));
            stop.setIconSclass("z-icon-remove");
            stop.setSclass("ml-2");
            stop.setAttribute("s", 1);
            stop.addEventListener(Events.ON_CLICK, el);
            stop.setParent(span);

            Button log = new Button(Labels.getLabel("admin.menu.real.log"));
            log.setIconSclass("z-icon-history");
            log.setSclass("ml-2");
            log.setAttribute("s", 2);
            log.addEventListener(Events.ON_CLICK, el);
            log.setParent(span);

            Button wf = new Button(Labels.getLabel("admin.user.wf"));
            wf.setIconSclass("z-icon-bars");
            wf.setSclass("ml-2");
            wf.setAttribute("s", 3);
            wf.addEventListener(Events.ON_CLICK, el);
            wf.setParent(span);

            row.appendChild(span);
            row.setValue(s);
            users.getRows().appendChild(row);
        }
    }

    @Listen("onOpen=#search")
    public void onSearch(Event evt) {
        OpenEvent oe = (OpenEvent) evt;
        String val = (String) oe.getValue();
        if (Strings.isBlank(val)) {
            onRefresh();
        } else {
            List<ServiceVo> list = new ArrayList<>();
            for (ServiceVo s : model) {
                if (s.getId().indexOf(val) >= 0 || s.getName().indexOf(val) >= 0)
                    list.add(s);
            }
            users.getRows().getChildren().clear();
            createList(list);
        }
    }

    @Listen("onClick=#refresh")
    public void onRefresh() {
        users.getRows().getChildren().clear();
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(new SimpleRequestMessage(ServiceType.USER));
        if (resp.isSuccess()) {
            model = (List<ServiceVo>) resp.getBody();
            nums.setValue(Labels.getLabel("admin.user.nums") + ":" + model.size());
            createList(model);
        } else {
            MessageBox.showMessage(resp);
        }
    }

    public void onWorkbench(Event event) {
        final ServiceVo vo = ((Row) event.getTarget().getParent().getParent()).getValue();
        Map<String, Object> args = new HashMap<>();
        args.put("s", vo);
        Executions.createComponents("~./admin/wf.zul", null, args);
    }

    private void onShowLog(final Event evt) {
        final ServiceVo vo = ((Row) evt.getTarget().getParent().getParent()).getValue();
        Map<String, Object> args = new HashMap<>();
        args.put("s", vo);
        Executions.createComponents("~./admin/log_dialog.zul", null, args);
    }

    private void onLock(final Event evt) {
        final ServiceVo vo = ((Row) evt.getTarget().getParent().getParent()).getValue();
        if (!Contexts.getUser().getId().equals(vo.getId())) {
            Messagebox.show(Labels.getLabel(
                    "admin.service.op.confirm",
                    new Object[]{vo.getState() == StateType.START ? Labels
                            .getLabel("admin.service.pause") : Labels
                            .getLabel("admin.service.resume")}), Labels
                            .getLabel("admin.service.op.title"), Messagebox.CANCEL
                            | Messagebox.OK, Messagebox.QUESTION,
                    new EventListener<Event>() {

                        @Override
                        public void onEvent(Event event) throws Exception {
                            if (event.getName().equals(Messagebox.ON_OK)) {
                                int state = vo.getState();
                                if (state == StateType.START)
                                    state = StateType.PAUSE;
                                else
                                    state = StateType.START;

                                AdminService as = ServiceLocator
                                        .lookup(AdminService.class);
                                IResponseMessage<?> resp = as
                                        .setServiceState(new ServiceRequestMessage(
                                                new ServiceVo(vo.getAsString("session"), ServiceType.USER, state)));
                                if (resp.isSuccess()) {
                                    vo.setState(state);
                                    Button op = (Button) evt.getTarget();
                                    if (vo.getState() == StateType.START) {
                                        op.setIconSclass("z-icon-cog z-icon-spin");
                                        op.setLabel(Labels.getLabel("admin.service.state.blocked"));
                                    } else {
                                        op.setIconSclass("z-icon-lock");
                                        op.setLabel(Labels.getLabel("admin.service.state.paused"));
                                    }
                                } else
                                    MessageBox.showMessage(resp);
                            }
                        }
                    });
        } else
            MessageBox
                    .showMessage(
                            Labels.getLabel("admin.service.op.title"),
                            Labels.getLabel(
                                    "admin.service.op.self",
                                    new Object[]{
                                            vo.getId(),
                                            vo.getState() == StateType.START ? Labels
                                                    .getLabel("admin.service.pause")
                                                    : Labels.getLabel("admin.service.resume")}));
    }

    private void onStop(final Event evt) {
        final ServiceVo vo = ((Row) evt.getTarget().getParent().getParent()).getValue();
        if (!Lang.equals(evt.getTarget().getDesktop().getSession().getAttribute(Constants.SESSION_ID), vo.getValue("session"))) {
            Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                    new Object[]{Labels.getLabel("admin.service.stop")}),
                    Labels.getLabel("admin.service.op.title"),
                    Messagebox.CANCEL | Messagebox.OK, Messagebox.QUESTION,
                    new EventListener<Event>() {

                        @Override
                        public void onEvent(Event event) throws Exception {
                            if (event.getName().equals(Messagebox.ON_OK)) {
                                vo.setState(StateType.STOP);
                                AdminService as = ServiceLocator
                                        .lookup(AdminService.class);
                                IResponseMessage<?> resp = as
                                        .setServiceState(new ServiceRequestMessage(
                                                new ServiceVo(vo.getAsString("session"), ServiceType.USER, vo.getState())));
                                if (resp.isSuccess()) {
                                    evt.getTarget().getParent().getParent().detach();
                                    model.remove(vo);
                                    nums.setValue(Labels.getLabel("admin.user.nums") + ":" + model.size());
                                } else
                                    MessageBox.showMessage(resp);
                            }
                        }
                    });
        } else
            MessageBox.showMessage(
                    Labels.getLabel("admin.service.op.title"),
                    Labels.getLabel(
                            "admin.service.op.self",
                            new Object[]{vo.getId(),
                                    Labels.getLabel("admin.service.stop")}));
    }
}
